//  Copyright Druid Mechanics

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "AuraPlayerController.generated.h"


class IHighlightInterface;
class AMagicCircle;
class UNiagaraSystem;
class UInputMappingContext;
class UAuraInputConfig;
struct FGameplayTag;
class USplineComponent;

UENUM(BlueprintType)
enum class ETargetingStatus : uint8
{
	TargetingEnemy,
	TargetingNonEnemy,
	NoTargeting
};

/**
 * UInputAction: 输入行为定义，这是每个玩家的实例(凭借FInputActionInstance)。
 */
class UInputAction;
/**
 * Boolean			UMETA(DisplayName = "Digital (bool)")
 * Axis1D				UMETA(DisplayName = "Axis1D (float)")
 * Axis2D				UMETA(DisplayName = "Axis2D (Vector2D)") 左右对应X轴(AD)，上下对应Y轴(WS)
 * Axis3D				UMETA(DisplayName = "Axis3D (Vector)")
 */
struct FInputActionValue;
class UAuraAbilitySystemComponent;
class UDamageTextComponent;

/**
 * 
 */
UCLASS()
class AURA_API AAuraPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	AAuraPlayerController();
	/**
	 * 处理玩家输入(在玩家获取Tick后立即执行)并执行UpdateRotation()。
	 * 仅在玩家控制器有PlayerInput对象时PlayerTick调用。
	 * 因此，它仅在本地玩家控制器执行。
	 *
	 * PlayerController用PlayerTick，Character中有Tick函数，什么时候用PlayerTick什么时候用Tick。
	 * PlayerTick只能用于本地Controller，不能用于服务端和非本地的Controller；Tick则不受限制。
	 * LINK: https://blog.csdn.net/wag2765/article/details/84771183
	 */
	virtual void PlayerTick(float DeltaTime) override;
	UFUNCTION(Client, Reliable)
	void ShowDamageNumber(float DamageAmount, ACharacter* TargetCharacter, bool bBlockedHit, bool bCriticalHit);
	UFUNCTION(BlueprintCallable)
	void ShowMagicCircle(UMaterialInterface* DecalMaterial = nullptr);
	UFUNCTION(BlueprintCallable)
	void HideMagicCircle();

protected:
	virtual void BeginPlay() override;
	virtual void SetupInputComponent() override;

private:
	/**
	 * TObjectPtr: 
	 * TObjectPtr是一种指向UObject的指针，旨在作为原始指针成员属性的插入式替换。
	 * 它的大小相当于一个64位指针，支持访问跟踪和编辑器构建中的可选延迟加载行为。
	 * 它存储被引用对象的地址，或者(在编辑器构建中)在对象句柄表中存储一个索引，该索引描述了尚未加载的被引用对象。
	 * 它被序列化为指向UObject的原始指针。解析后，它在垃圾收集中的参与与指向UObject的原始指针相同。
	 */
	/**
	 * UInputMappingContext: 对于具体输入上下文行为映射的键集合。
	 * 能够用来: 存储预设的控制器映射(允许在各种控制器配置之间切换)。
	 */
	UPROPERTY(EditAnywhere, Category = "Input")
	TObjectPtr<UInputMappingContext> AuraContext;

	UPROPERTY(EditAnywhere, Category = "Input")
	TObjectPtr<UInputAction> MoveAction;

	UPROPERTY(EditAnywhere, Category = "Input")
	TObjectPtr<UInputAction> ShiftAction;

	void ShiftPressed() { bShiftKeyDown = true; };

	void ShiftReleased() { bShiftKeyDown = false; };

	bool bShiftKeyDown{false};

	void Move(const FInputActionValue& InputActionValue);

	void CursorTrace();

	TObjectPtr<AActor> LastActor;
	TObjectPtr<AActor> ThisActor;
	FHitResult CursorHit;

	static void HighlightActor(AActor* InActor);
	static void UnHighlightActor(AActor* InActor);

	void AbilityInputTagPressed(FGameplayTag InputTag);
	void AbilityInputTagReleased(FGameplayTag InputTag);
	void AbilityInputTagHeld(FGameplayTag InputTag);

	UPROPERTY(EditDefaultsOnly, Category = "Input")
	TObjectPtr<UAuraInputConfig> InputConfig;

	UPROPERTY()
	TObjectPtr<UAuraAbilitySystemComponent> AuraAbilitySystemComponent;

	UAuraAbilitySystemComponent* GetASC();

	FVector CachedDestination{FVector::ZeroVector};
	float FollowTime{0.f};
	float ShortPressThreshold{0.5f};
	bool bAutoRunning{false};
	
	ETargetingStatus TargetingStatus{ETargetingStatus::NoTargeting};

	UPROPERTY(EditDefaultsOnly)
	float AutoRunAcceptanceRadius{50.f};
	/**
	 * USplineComponent: 样条线组件是一种样条线形状，可用于其他目的（例如为对象设置动画）。它包含调试渲染功能。
	 */
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<USplineComponent> Spline;

	UPROPERTY(EditDefaultsOnly)
	TObjectPtr<UNiagaraSystem> ClickNiagaraSystem;

	void AutoRun();

	UPROPERTY(EditDefaultsOnly)
	TSubclassOf<UDamageTextComponent> DamageTextComponentClass;

	UPROPERTY(EditDefaultsOnly)
	TSubclassOf<AMagicCircle> MagicCircleClass;
	UPROPERTY()
	TObjectPtr<AMagicCircle> MagicCircle;

	void UpdateMagicCircleLocation();
};
